package com.jxs.android.weiget;

import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Scroller;

public class VerticalFlipperWidget extends ViewGroup {

	public interface IViewFlipperChild {
		boolean isSkipFlipperFlingHandleNow();
	}

	private Scroller scroller;
	private int currentScreenIndex = 0;
	private GestureDetector gestureDetector;

	private OnMainFlipperListener mainFilpperListener = null;

	private boolean fling;

	public void setMainFilpperListener(OnMainFlipperListener listener) {
		mainFilpperListener = listener;
	}

	public int getContainerSize() {
		return getChildCount();
	}

	public int GetCurrentViewIndex() {
		return currentScreenIndex;
	}

	public void setToScreen(int currentScreenIndex) {
		this.currentScreenIndex = Math.max(0, Math.min(currentScreenIndex, getChildCount()));
		scrollTo(0, this.currentScreenIndex * getHeight());
		invalidate();
	}

	public Scroller getScroller() {
		return scroller;
	}

	public VerticalFlipperWidget(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		initView(context);
	}

	public VerticalFlipperWidget(Context context, AttributeSet attrs) {
		super(context, attrs);
		initView(context);
	}

	public VerticalFlipperWidget(Context context) {
		super(context);
		initView(context);
	}

	private void initView(final Context context) {
		this.scroller = new Scroller(context);

		setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));

		this.gestureDetector = new GestureDetector(new OnGestureListener() {

			@Override
			public boolean onSingleTapUp(MotionEvent e) {
				return false;
			}

			@Override
			public void onShowPress(MotionEvent e) {
			}

			@Override
			public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
				return false;
			}

			@Override
			public void onLongPress(MotionEvent e) {
			}

			@Override
			public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

				if (Math.abs(velocityY) < Math.abs(velocityX)) {
					return false;
				}
				if (((IViewFlipperChild) getChildAt(currentScreenIndex)).isSkipFlipperFlingHandleNow()) {
					return false;
				}
				if (Math.abs(velocityY) > ViewConfiguration.get(context).getScaledMinimumFlingVelocity() * 3) {

					if (velocityY > 0 && currentScreenIndex > 0) {
						fling = true;
						snapToScreen(currentScreenIndex - 1);
					} else if (velocityY < 0 && currentScreenIndex < getChildCount() - 1) {
						fling = true;
						snapToScreen(currentScreenIndex + 1);
					}
				}

				return true;
			}

			@Override
			public boolean onDown(MotionEvent e) {
				return false;
			}
		});
	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
		for (int i = 0; i < getChildCount(); i++) {
			View child = getChildAt(i);
			if (child != null) {
				child.setVisibility(View.VISIBLE);
				child.layout(0, 0 + i * getHeight(), getWidth(), (i + 1) * getHeight());
			}
		}
		setToScreen(currentScreenIndex);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);

		final int height = MeasureSpec.getSize(heightMeasureSpec);
		final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
		if (heightMode != MeasureSpec.EXACTLY) {
			throw new IllegalStateException("ScrollLayout only can run at EXACTLY mode!");
		}

		final int widthMode = MeasureSpec.getMode(heightMeasureSpec);
		if (widthMode != MeasureSpec.EXACTLY) {
			throw new IllegalStateException("ScrollLayout only can run at EXACTLY mode!");
		}

		final int count = getChildCount();
		for (int i = 0; i < count; i++) {
			getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
		}
		scrollTo(0, currentScreenIndex * height);
	}

	@Override
	public void computeScroll() {
		if (scroller.computeScrollOffset()) {
			scrollTo(0, scroller.getCurrY());
			postInvalidate();
		}
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {

		gestureDetector.onTouchEvent(event);
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			break;
		case MotionEvent.ACTION_MOVE:
			break;
		case MotionEvent.ACTION_UP:
			if (!fling) {
				snapToDestination();
			}
			fling = false;
			if (mainFilpperListener != null) {
				mainFilpperListener.onTouchUp();
			}
			break;
		default:
			break;
		}
		super.onTouchEvent(event);
		return true;
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		super.onInterceptTouchEvent(ev);
		return this.gestureDetector.onTouchEvent(ev);
	}

	public void snapToScreen(int whichScreen) {
		if (getFocusedChild() != null && whichScreen != currentScreenIndex && getFocusedChild() == getChildAt(currentScreenIndex)) {
			getFocusedChild().clearFocus();
		}

		final int delta = whichScreen * getHeight() - getScrollY();
		scroller.startScroll(0, getScrollY(), 0, delta, Math.abs(delta) * 2);
		invalidate();

		currentScreenIndex = whichScreen;
	}

	private void snapToDestination() {
		snapToScreen((getScrollY() + (getHeight() / 2)) / getHeight());
	}

	public interface OnMainFlipperListener {
		public void onTouchUp();
	}
}
